package pacman.entries.pacman;

import java.util.Random;

import pacman.controllers.Controller;
import pacman.game.Constants.GHOST;
import pacman.game.Constants.MOVE;
import pacman.game.Game;

/*
 * This is the class you need to modify for your entry. In particular, you need to
 * fill in the getAction() method. Any additional classes you write should either
 * be placed in this package or sub-packages (e.g., game.entries.pacman.mypackage).
 */
public class MyPacMan extends Controller<MOVE>
{
	Node next; //the next node that pacman is traveling to
	boolean step = false; //true on the tick immediately after a node (to see which path was chosen by pacman/ghosts and choose the next node accordingly)
	Random rand = new Random();
	long lastGameTime;
	public static Game gg;

	@Override
	public MOVE getMove(Game game, long timeDue)
	{
		gg = game;
		//if any of these are true, we start over searching
		if (game.wasPacManEaten() //because it doesn't search beyond death
				|| (game.getTimeOfLastGlobalReversal() == game.getTotalTime() - 1 && !game.wasPowerPillEaten()) //because it doesn't search reversals (despite the documentation, power pill reversals seem to trigger this, so the second part is necessary)
				|| game.getCurrentLevelTime() == 0 //because it doesn't search beyond level end
				|| game.getTotalTime() != lastGameTime + 1) //skipped tick
		{
			next = new Node(new MyGame(game));
			next.evaluateRoot(timeDue - 20);
		} else if (step) //indicating we must select the next node, now that we know what the ghosts chose
		{
			next = next.getChild(new int[] {
					game.getCurrentLevel(),
					game.getPacmanCurrentNodeIndex(),
					game.getGhostCurrentNodeIndex(GHOST.BLINKY), game.getGhostCurrentNodeIndex(GHOST.PINKY), game.getGhostCurrentNodeIndex(GHOST.INKY), game.getGhostCurrentNodeIndex(GHOST.SUE)
			}); //see documentation in Node

			//this should only happen when pacman accidentally skips a tick and thus doesn't detect the next gamestate properly
			//hopefully can make the detection more robust in the future 
			if (next == null)
			{
				next = new Node(new MyGame(game));
				next.evaluateRoot(timeDue - 20);
			}
		}
		step = false;
		lastGameTime = game.getTotalTime();

		//uncomment this to highlight what Pacman's next target is
		//		GameView.addPoints(game, Color.YELLOW, next.getPacmanLocation());

		//indicates pacman reached the destination; again, can be more robust
		//note that setting lastMove will cause the controller to return that as the next move, even if this method doesn't return on time
		if (game.getPacmanCurrentNodeIndex() == next.getPacmanLocation())
		{
			step = true; //stepping to the next node on the following tick because we don't know what the ghosts will do until then
			double[] probabilities = next.getProbabilities(); //probabilities of going up, right, down, left based on minimax
			double strategy = rand.nextDouble();
			double upperBound = 0;
			for (int i = 0; i < 4; i++)
			{
				upperBound += probabilities[i];
				if (strategy < upperBound || i == 3)
				{
					lastMove = Node.MOVES[i];
					break;
				}
			}
		} else
		{
			lastMove = MOVE.NEUTRAL; //if pacman didn't reach the destination, just keep going
		}
		//initialDepth = next.evaluateRoot(initialDepth, System.currentTimeMillis() + 40); //search deeper with what time we have left
		next.evaluateRoot(timeDue - 10);
		return lastMove;
	}
}
